home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 6 code / TCP / NewsWatcher / NW Source / Source / next.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-04  |  13.5 KB  |  505 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     next.c
  4.  
  5.     This module handles the next article, thread, and group commands.
  6.     
  7.     Copyright © 1994-1995, Northwestern University.
  8.  
  9. ----------------------------------------------------------------------------*/
  10.  
  11. #include "glob.h"
  12. #include "article.h"
  13. #include "newswatcher.h"
  14. #include "mark.h"
  15. #include "next.h"
  16. #include "subject.h"
  17. #include "listutil.h"
  18. #include "dialog.h"
  19. #include "dummy.h"
  20. #include "help.h"
  21.  
  22.  
  23.  
  24. /*----------------------------------------------------------------------------
  25.     OpenNextUnreadGroup 
  26.     
  27.     Open the subject window for the next group with unread articles in a 
  28.     group window.
  29.             
  30.     Entry:    wind = pointer to group window.
  31.             theCell = the cell in the group window at which to start
  32.                 the search for the next group with unread articles.
  33.                 
  34.     Exit:    function result = error code.
  35. ----------------------------------------------------------------------------*/
  36.  
  37. static OSErr OpenNextUnreadGroup (WindowPtr wind, Cell theCell)
  38. {
  39.     TWindow **info;
  40.     TGroupWindowKind groupKind;
  41.     TGroup **groupArray, theGroup;
  42.     ListHandle theList;
  43.     short numCells, cellDataLen, index;
  44.     OSErr err = noErr;
  45.     Boolean hasArts;
  46.  
  47.     info = (TWindow**)GetWRefCon(wind);
  48.     groupKind = (**info).groupKind;
  49.     groupArray = (**info).groupArray;
  50.     theList = (**info).theList;
  51.     numCells = (**theList).dataBounds.bottom;
  52.     for (; theCell.v < numCells; theCell.v++) {
  53.         cellDataLen = 2;
  54.         LGetCell(&index, &cellDataLen, theCell, theList);
  55.         theGroup = (*groupArray)[index];
  56.         if ((groupKind == kUserGroup && theGroup.unread != nil) ||
  57.             (groupKind != kUserGroup && theGroup.lastMess >= theGroup.firstMess)) 
  58.         {
  59.             SelectSingleListItem(theList, theCell);
  60.             HandleUpdate(wind);
  61.             MyLAutoScroll(theList);
  62.             err = OpenGroupCell(wind, theCell, gPrefs.maxFetch, &hasArts);
  63.             if (err != noErr) return err;
  64.             if (err == noErr && hasArts) return noErr;
  65.         }
  66.     }
  67.     if (gPrefs.beepAtEndOfLists) SysBeep(0);
  68.     return noErr;
  69. }
  70.  
  71.  
  72.  
  73. /*----------------------------------------------------------------------------
  74.     OpenNextUnreadArticle 
  75.     
  76.     Open the article window for the next unread article in a subject window.
  77.             
  78.     Entry:    wind = pointer to subject window.
  79.             theCell = the cell in the subject window at which to start
  80.                 the search for the next unread article.
  81.             threadOrdinal = ordinal of article within thread at which
  82.                 to start the search if the cell is a collapsed thread.
  83.             reuse = pointer to article window to be reused, or nil to
  84.                 open new article window.
  85.             onlySelect = true to only select the next unrread article
  86.                 in the subject window, but not open it.
  87.                 
  88.     Exit:    function result = error code.
  89. ----------------------------------------------------------------------------*/
  90.  
  91. static OSErr OpenNextUnreadArticle (WindowPtr wind, Cell theCell, 
  92.     short threadOrdinal, WindowPtr reuse, Boolean onlySelect)
  93. {
  94.     TWindow **info;
  95.     TSubject **subjectArray;
  96.     ListHandle theList;
  97.     short numCells, cellDataLen, index, i;
  98.     Boolean collapsed;
  99.     WindowPtr child, parent;
  100.     OSErr err = noErr;
  101.  
  102.     info = (TWindow**)GetWRefCon(wind);
  103.     subjectArray = (**info).subjectArray;
  104.     theList = (**info).theList;
  105.     numCells = (**theList).dataBounds.bottom;
  106.     while (theCell.v < numCells) {
  107.         cellDataLen = 2;
  108.         LGetCell(&index, &cellDataLen, theCell, theList);
  109.         if (threadOrdinal > (*subjectArray)[index].threadLength) {
  110.             theCell.v++;
  111.             threadOrdinal = 1;
  112.         } else {
  113.             collapsed = (*subjectArray)[index].collapsed;
  114.             if (collapsed) 
  115.                 for (i = 1; i < threadOrdinal; i++) 
  116.                     index = (*subjectArray)[index].nextInThread;
  117.             if (!(*subjectArray)[index].read) { 
  118.                 SelectSingleListItem(theList, theCell);
  119.                 HandleUpdate(wind);
  120.                 MyLAutoScroll(theList);
  121.                 if (onlySelect) return noErr;
  122.                 err = OpenSubjectCell(wind, theCell, threadOrdinal, reuse, &child);
  123.                 if (err != noErr) return err;
  124.                 if (child != nil) return noErr;
  125.             }
  126.             if (collapsed) {
  127.                 threadOrdinal++;
  128.             } else {
  129.                 theCell.v++;
  130.                 threadOrdinal = 1;
  131.             }
  132.         }
  133.     }
  134.     if (reuse != nil) DoClose(reuse);
  135.     if (gPrefs.stopAtEndOfSubjectList) {
  136.         if (gPrefs.beepAtEndOfLists) SysBeep(0);
  137.     } else {
  138.         parent = (**info).parentWindow;
  139.         index = (**info).parentGroup;
  140.         err = DoClose(wind);
  141.         if (err != noErr) return err;
  142.         wind = parent;
  143.         FindParentCell(wind, index, &theCell);
  144.         theCell.v++;
  145.         return OpenNextUnreadGroup(wind, theCell);
  146.     }
  147.     return noErr;
  148. }
  149.  
  150.  
  151.  
  152. /*----------------------------------------------------------------------------
  153.     DoNextArticle 
  154.     
  155.     Handle the "Next Article" command.
  156.             
  157.     Entry:    wind = pointer to article, subject, or group window.
  158.     
  159.     Exit:    function result = error code.
  160. ----------------------------------------------------------------------------*/
  161.  
  162. OSErr DoNextArticle (WindowPtr wind)
  163. {
  164.     TWindow **info;
  165.     WindowPtr parent;
  166.     short index, threadOrdinal;
  167.     TSubject **subjectArray, theSubject;
  168.     Cell theCell;
  169.     Boolean returnToSubjectWindow = false;
  170.     OSErr err = noErr;
  171.     
  172.     info = (TWindow**)GetWRefCon(wind);
  173.     
  174.     switch ((**info).kind) {
  175.     
  176.         case kArticle:
  177.         
  178.             parent = (**info).parentWindow;
  179.             if (parent == nil) return noErr;
  180.             index = (**info).parentSubject;
  181.             info = (TWindow**)GetWRefCon(parent);
  182.             subjectArray = (**info).subjectArray;
  183.             theSubject = (*subjectArray)[index];
  184.             if (theSubject.collapsed) {
  185.                 FindParentCell(parent, theSubject.threadHeadIndex, &theCell);
  186.                 threadOrdinal = theSubject.threadOrdinal + 1;
  187.             } else {
  188.                 FindParentCell(parent, index, &theCell);
  189.                 theCell.v++;
  190.                 threadOrdinal = 1;
  191.             }
  192.             
  193.             if (gPrefs.returnToSubjectWindow) {
  194.                 returnToSubjectWindow = true;
  195.                 while (true) {
  196.                     if (theSubject.threadOrdinal == theSubject.threadLength) break;
  197.                     theSubject = (*subjectArray)[theSubject.nextInThread];
  198.                     if (!theSubject.read) {
  199.                         returnToSubjectWindow = false;
  200.                         break;
  201.                     }
  202.                 }
  203.             }
  204.             
  205.             if (returnToSubjectWindow) {
  206.                 err = DoClose(wind);
  207.                 if (err != noErr) return err;
  208.                 return OpenNextUnreadArticle(parent, theCell, threadOrdinal, nil, true);
  209.             } else if (gPrefs.reuseArticleWinds) {
  210.                 return OpenNextUnreadArticle(parent, theCell, threadOrdinal, wind, false);
  211.             } else {
  212.                 err = DoClose(wind);
  213.                 if (err != noErr) return err;
  214.                 err = ShowDummyWindow();
  215.                 if (err != noErr) return err;
  216.                 err = OpenNextUnreadArticle(parent, theCell, threadOrdinal, nil, false);
  217.                 HideDummyWindow();
  218.                 return err;
  219.             }
  220.             
  221.         case kSubject:
  222.         
  223.             SetPt(&theCell, 0, 0);
  224.             LGetSelect(true, &theCell, (**info).theList);
  225.             threadOrdinal = 1;
  226.             return OpenNextUnreadArticle(wind, theCell, threadOrdinal, nil, false);
  227.             
  228.         case kGroup:
  229.         
  230.             SetPt(&theCell, 0, 0);
  231.             LGetSelect(true, &theCell, (**info).theList);
  232.             return OpenNextUnreadGroup(wind, theCell);
  233.             
  234.     }
  235.     return noErr;
  236. }
  237.  
  238.  
  239.  
  240. /*----------------------------------------------------------------------------
  241.     DoNextThread 
  242.     
  243.     Handle the "Next Thread" command.
  244.             
  245.     Entry:    wind = pointer to article, subject, or group window.
  246.     
  247.     Exit:    function result = error code.
  248. ----------------------------------------------------------------------------*/
  249.  
  250. OSErr DoNextThread (WindowPtr wind)
  251. {
  252.     TWindow **info;
  253.     WindowPtr parent;
  254.     short index, cellDataLen;
  255.     TSubject **subjectArray, theSubject;
  256.     Cell theCell;
  257.     ListHandle theList;
  258.     OSErr err = noErr;
  259.     
  260.     info = (TWindow**)GetWRefCon(wind);
  261.     
  262.     switch ((**info).kind) {
  263.     
  264.         case kArticle:
  265.         
  266.             parent = (**info).parentWindow;
  267.             if (parent == nil) return noErr;
  268.             index = (**info).parentSubject;
  269.             info = (TWindow**)GetWRefCon(parent);
  270.             subjectArray = (**info).subjectArray;
  271.             theSubject = (*subjectArray)[index];
  272.             MarkThread(parent, theSubject.threadHeadIndex, true);
  273.             FindParentCell(parent, theSubject.threadHeadIndex, &theCell);
  274.             if (theSubject.collapsed) {
  275.                 theCell.v++;
  276.             } else {
  277.                 theCell.v += theSubject.threadLength;
  278.             }
  279.             
  280.             if (gPrefs.reuseArticleWinds) {
  281.                 return OpenNextUnreadArticle(parent, theCell, 1, wind, false);
  282.             } else {
  283.                 err = DoClose(wind);
  284.                 if (err != noErr) return err;
  285.                 err = ShowDummyWindow();
  286.                 if (err != noErr) return err;
  287.                 err = OpenNextUnreadArticle(parent, theCell, 1, nil, false);
  288.                 HideDummyWindow();
  289.                 return err;
  290.             }
  291.             
  292.         case kSubject:
  293.         
  294.             theList = (**info).theList;
  295.             subjectArray = (**info).subjectArray;
  296.             SetPt(&theCell, 0, 0);
  297.             if (LGetSelect(true, &theCell, theList)) {
  298.                 cellDataLen = 2;
  299.                 LGetCell(&index, &cellDataLen, theCell, theList);
  300.                 theSubject = (*subjectArray)[index];
  301.                 MarkThread(wind, theSubject.threadHeadIndex, true);
  302.                 if (theSubject.collapsed) {
  303.                     theCell.v++;
  304.                 } else {
  305.                     theCell.v += theSubject.threadLength + 1 - theSubject.threadOrdinal;
  306.                 }
  307.             }
  308.             return OpenNextUnreadArticle(wind, theCell, 1, nil, false);
  309.             
  310.         case kGroup:
  311.         
  312.             SetPt(&theCell, 0, 0);
  313.             LGetSelect(true, &theCell, (**info).theList);
  314.             return OpenNextUnreadGroup(wind, theCell);
  315.             
  316.     }
  317.     return noErr;
  318. }
  319.  
  320.  
  321.  
  322. /*----------------------------------------------------------------------------
  323.     DoNextGroup 
  324.     
  325.     Handle the "Next Group" command.
  326.             
  327.     Entry:    wind = pointer to article, subject, or group window.
  328.     
  329.     Exit:    function result = error code.
  330. ----------------------------------------------------------------------------*/
  331.  
  332. OSErr DoNextGroup (WindowPtr wind)
  333. {
  334.     TWindow **info;
  335.     WindowPtr parent;
  336.     short index;
  337.     Cell theCell;
  338.     OSErr err = noErr;
  339.     
  340.     info = (TWindow**)GetWRefCon(wind);
  341.     
  342.     switch ((**info).kind) {
  343.     
  344.         case kArticle:
  345.         
  346.             parent = (**info).parentWindow;
  347.             if (parent == nil) return noErr;
  348.             err = DoClose(wind);
  349.             if (err != noErr) return err;
  350.             wind = parent;
  351.             info = (TWindow**)GetWRefCon(wind);
  352.             /* fall through to kSubject case */;
  353.             
  354.         case kSubject:
  355.         
  356.             MarkAllSubjects(wind, true);
  357.             parent = (**info).parentWindow;
  358.             index = (**info).parentGroup;
  359.             err = DoClose(wind);
  360.             if (err != noErr) return err;
  361.             wind = parent;
  362.             FindParentCell(wind, index, &theCell);
  363.             theCell.v++;
  364.             return OpenNextUnreadGroup(wind, theCell);
  365.             
  366.         case kGroup:
  367.         
  368.             SetPt(&theCell, 0, 0);
  369.             LGetSelect(true, &theCell, (**info).theList);
  370.             return OpenNextUnreadGroup(wind, theCell);
  371.             
  372.     }
  373.     return noErr;
  374. }
  375.  
  376.  
  377.  
  378. /*----------------------------------------------------------------------------
  379.     OpenPrevOrNextArticle 
  380.     
  381.     Open the previous or next article.
  382.             
  383.     Entry:    parent = pointer to parent subject window.
  384.             theCell = the parent cell in the subject window for the article.
  385.             threadOrdinal = ordinal of article within thread if thread
  386.                 is collapsed, else 1.
  387.             reuse = pointer to article window to be reused, or nil to
  388.                 open new article window.
  389.             dir = direction = -1 to open previous article, +1 to open
  390.                 next article.
  391.                 
  392.     Exit:    function result = error code.
  393. ----------------------------------------------------------------------------*/
  394.  
  395. static OSErr OpenPrevOrNextArticle (WindowPtr parent, Cell theCell, 
  396.     short threadOrdinal, WindowPtr reuse, short dir)
  397. {
  398.     TWindow **info;
  399.     TSubject **subjectArray;
  400.     ListHandle theList;
  401.     short numCells, cellDataLen, index;
  402.     WindowPtr child;
  403.     OSErr err = noErr;
  404.  
  405.     info = (TWindow**)GetWRefCon(parent);
  406.     subjectArray = (**info).subjectArray;
  407.     theList = (**info).theList;
  408.     numCells = (**theList).dataBounds.bottom;
  409.     cellDataLen = 2;
  410.     LGetCell(&index, &cellDataLen, theCell, theList);
  411.     while (true) {
  412.         if ((*subjectArray)[index].collapsed) {
  413.             threadOrdinal += dir;
  414.             if (threadOrdinal > (*subjectArray)[index].threadLength) {
  415.                 theCell.v++;
  416.                 if (theCell.v >= numCells) break;
  417.                 threadOrdinal = 1;
  418.                 cellDataLen = 2;
  419.                 LGetCell(&index, &cellDataLen, theCell, theList);
  420.             } else if (threadOrdinal <= 0) {
  421.                 theCell.v--;
  422.                 if (theCell.v < 0) break;
  423.                 LGetCell(&index, &cellDataLen, theCell, theList);
  424.                 if ((*subjectArray)[index].collapsed) {
  425.                     threadOrdinal = (*subjectArray)[index].threadLength;
  426.                 } else {
  427.                     threadOrdinal = 1;
  428.                 }
  429.             }
  430.         } else {
  431.             theCell.v += dir;
  432.             if (theCell.v >= numCells || theCell.v < 0) break;
  433.             cellDataLen = 2;
  434.             LGetCell(&index, &cellDataLen, theCell, theList);
  435.             if (dir == -1 && (*subjectArray)[index].collapsed) {
  436.                 threadOrdinal = (*subjectArray)[index].threadLength;
  437.             } else {
  438.                 threadOrdinal = 1;
  439.             }
  440.         }
  441.         SelectSingleListItem(theList, theCell);
  442.         HandleUpdate(parent);
  443.         MyLAutoScroll(theList);
  444.         err = OpenSubjectCell(parent, theCell, threadOrdinal, reuse, &child);
  445.         if (err != noErr) return err;
  446.         if (child != nil) return noErr;
  447.     }
  448.     SysBeep(0);
  449.     return noErr;
  450. }
  451.  
  452.  
  453. /*----------------------------------------------------------------------------
  454.     GoBackwardsOrForwardsOneArticle
  455.     
  456.     Go backwards or forwards one article.
  457.     
  458.     Entry:    wind = pointer to article window.
  459.             dir = direction = -1 to go backwards, +1 to go forwards.
  460.             
  461.     Exit:    function result = error code.
  462. ----------------------------------------------------------------------------*/
  463.  
  464. OSErr GoBackwardsOrForwardsOneArticle (WindowPtr wind, short dir)
  465. {
  466.     TWindow **info;
  467.     WindowPtr parent;
  468.     short index, threadOrdinal;
  469.     TSubject **subjectArray, theSubject;
  470.     Cell theCell;
  471.     Boolean returnToSubjectWindow = false;
  472.     OSErr err = noErr;
  473.     
  474.     info = (TWindow**)GetWRefCon(wind);
  475.     if ((**info).kind != kArticle) return noErr;
  476.     parent = (**info).parentWindow;
  477.     if (parent == nil) return noErr;
  478.     index = (**info).parentSubject;
  479.     info = (TWindow**)GetWRefCon(parent);
  480.     subjectArray = (**info).subjectArray;
  481.     theSubject = (*subjectArray)[index];
  482.     if (theSubject.collapsed) {
  483.         FindParentCell(parent, theSubject.threadHeadIndex, &theCell);
  484.         threadOrdinal = theSubject.threadOrdinal;
  485.     } else {
  486.         FindParentCell(parent, index, &theCell);
  487.         threadOrdinal = 1;
  488.     }
  489.     if (gPrefs.reuseArticleWinds) {
  490.         err = OpenPrevOrNextArticle(parent, theCell, threadOrdinal, wind, dir);
  491.     } else {
  492.         err = DoClose(wind);
  493.         if (err != noErr) goto exit;
  494.         err = ShowDummyWindow();
  495.         if (err != noErr) goto exit;
  496.         err = OpenPrevOrNextArticle(parent, theCell, threadOrdinal, nil, dir);
  497.         HideDummyWindow();
  498.     }
  499.  
  500. exit:
  501.  
  502.     KillBalloon();
  503.     return err;
  504. }
  505.